package com.example.latch;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Data
public class DbLeaderLeaderLatch implements LeaderLatch {

    Logger logger = LoggerFactory.getLogger(getClass());

    private ApplicationContext applicationContext;

    private LeaderLatchListener listener;

    private Thread thread;

    private DataSource dataSource;

    private Connection connection;

    private PreparedStatement preparedStatement;

    private volatile boolean isStop = false;

    private String sql = "select * from db_lock where id = 1 for update";

    public DbLeaderLeaderLatch(ApplicationContext applicationContext, LeaderLatchListener listener) {
        this.applicationContext = applicationContext;
        this.listener = listener;
        this.dataSource = applicationContext.getBean(DataSource.class);
    }

    @Override
    public void start() {
        this.thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!isStop) {
                    try {
                        connection = dataSource.getConnection();
                        connection.setAutoCommit(false);
                        preparedStatement = connection.prepareStatement(sql);
                        preparedStatement.execute();
                        //如果获取到锁，就跳出循环。
                        break;
                    } catch (SQLException exx) {
                        try {
                            logger.warn("get lock error " + exx.getMessage());
                        } finally {
                            //只能此处关闭连接
                            if (null != connection) {
                                try {
                                    connection.rollback();
                                } catch (SQLException e1) {
                                    logger.debug("Caught exception during rollback on connection");
                                }
                                try {
                                    connection.close();
                                } catch (SQLException e1) {
                                    logger.debug("Caught exception while closing connection");
                                }
                                connection = null;
                            }
                        }
                    } finally {
                        //关闭preparedStatement 但是不能关闭链接
                        if (null != preparedStatement) {
                            try {
                                preparedStatement.close();
                            } catch (SQLException e) {
                                logger.error(e.getMessage());
                            }
                        }
                    }
                }
                listener.isLeader();
            }
        });
        this.thread.start();
    }

    @Override
    public void stop() {
        isStop = true;
        if (this.thread.isAlive()) {
            this.thread.interrupt();
        }
        if (null != preparedStatement) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                logger.error(e.getMessage());
            }
        }
        if (null != connection) {
            try {
                connection.rollback();
            } catch (SQLException e1) {
                logger.debug("Caught exception during rollback on connection");
            }
            try {
                connection.close();
            } catch (SQLException e1) {
                logger.debug("Caught exception while closing connection");
            }
            connection = null;
        }
    }
}
